package com.huishi.handler.thread.task;


import com.huishi.entity.DataSource;
import com.huishi.entity.message.DBMsg;
import com.huishi.handler.thread.ThreadDataKeeper;
import com.huishi.ui.component.ProgressDialog;
import com.huishi.util.DBUtils;
import lombok.extern.slf4j.Slf4j;

import java.sql.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 数据库数据同步线程任务
 */
@Slf4j
public class SyncDataTask implements Runnable {

    private final DataSource sourceDS; // 源数据源
    private final String sourceDB; // 源库名
    private final DataSource targetDS; // 目标数据源
    private final String targetDB; // 目标库名


    private final List<String> tables; // 表
    private int processedRows = 0; // 已同步记录数
    private int totalRows = 0; // 总的记录数
    private final ProgressDialog progressDialog; // 同步状态框
    private final ThreadDataKeeper threadDataKeeper;
    private final Map<String, DBMsg> dbMsgMap;
    private final int batchSize = 1000; // 批量执行条数


    public SyncDataTask(DataSource sourceDS, String sourceDB, DataSource targetDS, String targetDB,
                        List<String> tables, ProgressDialog progressDialog, ThreadDataKeeper threadDataKeeper) {

        this.sourceDS = sourceDS;
        this.sourceDB = sourceDB;
        this.targetDS = targetDS;
        this.targetDB = targetDB;
        this.tables = tables;
        this.progressDialog = progressDialog;
        this.threadDataKeeper = threadDataKeeper;

        this.dbMsgMap = new HashMap<>(tables.size());
    }

    @Override
    public void run() {
//        try {
//            // beforeSyncTask执行完才能执行同步
//            this.beforeSyncTask.get();
//        } catch (InterruptedException | ExecutionException e) {
//            e.printStackTrace();
//        }

//        this.totalRows = threadDataKeeper.getTotalRows();
//        Map<String, DBMsg> dbMsgMap = this.threadDataKeeper.getDbSyncMsg();


        try (Connection sourceConn = DBUtils.genDBConn(sourceDS, sourceDB);
             Connection targetConn = DBUtils.genDBConn(targetDS, targetDB)) {


            beforeDataSync(sourceConn);
            log.info("开始同步----");

            // 遍历表 同步
            for (String table : tables) {
                progressDialog.updateStatus("Status: Synchronizing table " + table + "...", true);

                // 1创建表结构
                DBUtils.createTableToTarget(sourceConn, targetConn, table);

                // 2同步数据
                DBMsg dbMsg = dbMsgMap.get(table);
                String insertSQL = "INSERT INTO " + table + " VALUES (" + dbMsg.getPlaceholders() + ")";

                ResultSet resultSet = dbMsg.getResultSet();
                try (PreparedStatement targetStmt = targetConn.prepareStatement(insertSQL)) {

                    // 遍历源数据集插入目标表中
                    while (resultSet.next()) {
                        for (int i = 1; i <= dbMsg.getColumnCount(); i++) {

                            targetStmt.setObject(i, resultSet.getObject(i));
                        }
                        targetStmt.addBatch();

                        if (++processedRows % batchSize == 0) {
                            targetStmt.executeBatch();
                            updateProgress(processedRows);
                        }
                    }

                    // 执行剩余的批量
                    targetStmt.executeBatch();
                    updateProgress(processedRows); // 确保最后更新进度
                }

                progressDialog.updateStatus("Status: The " + table + " synchronize successfully", false);
            }

        } catch (Exception e) {
            log.error("同步出现异常：", e);
            progressDialog.updateStatus("Status: Error occurred =: " + DBUtils.getLastThrowable(e).getMessage(), true);
        }


    }

    /**
     * 更新同步进度
     *
     * @param processedRows
     */
    private void updateProgress(int processedRows) {
        int progress = (int) ((processedRows / (double) totalRows) * 100);
        progressDialog.updateProgress(progress);
    }


    /**
     * 同步前准备工作：获取每张表的记录、记录总数
     *
     * @param sourceConn
     * @throws SQLException
     */
    private void beforeDataSync(Connection sourceConn) throws SQLException {
        log.info("同步前准备工作：获取每张表的记录、记录总数");
        for (String table : this.tables) {
            String SQL = "SELECT * FROM " + table;

            Statement sourceStmt = sourceConn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);

            DBMsg dbMsg = new DBMsg();
            // 获取源所有记录
            long start = System.currentTimeMillis();
            ResultSet resultSet = sourceStmt.executeQuery(SQL);
            long end = System.currentTimeMillis();
            log.info("{}==beforeDataSync耗时：{}", table, end - start);

            // 获取记录总数
            resultSet.last();
            this.totalRows += resultSet.getRow();
            resultSet.beforeFirst();

            dbMsg.setResultSet(resultSet);
            dbMsg.setColumnCount(resultSet.getMetaData().getColumnCount());

            dbMsgMap.put(table, dbMsg);
        }
    }
}
